#pragma once
#include <queue>
#include <iostream>
#include "Mutex.hpp"
#include "Cond.hpp"

namespace BlockQueueModule
{
    using namespace LockModule;
    using namespace CondModule;

    const int gcap = 10;
    template <class T>
    class Blockqueue
    {
    private:
        bool Isfull() { return _cap == _bq.size(); }
        bool Isempty() { return _bq.empty(); }
    public:
        Blockqueue(int cap = gcap) : _cap(gcap), _p_count(0), _c_count(0)
        {
   
        }

        // 生产者生产数据
        void Equeue(T &data)
        {
            // 多线程访问临界资源需要加锁
            LockGuard lock(_mutex);
            // 2. 判读缓存是否已满
            while (Isfull()) //这里不能使用if，不然多-多可能会出问题!!
            {
                _p_count++;
                printf("生产者陷入等待\n");
                // 3. 陷入等待
                // 这里为什么要把锁带进去呢? - 你陷入等待你不能抱着锁陷入等待啊，不然没有意义了。
                // 那为什么被唤醒之后还要申请锁呢?? - 因为你在临界区中，必须要有锁。
                _productor_cond.Wait(_mutex);
                printf("生产者被唤醒\n");
                _p_count--;
            }
            // 4. 入数据
            _bq.push(data); // 1. 可以直接进入队列吗？？ 不可以!!
            // 5. 此时生产者一定知道有数据，唤醒一个消费者，让他来消费

            if (_c_count) //如果有消费者在等待
            {
                printf("唤醒消费者\n");
                _consumer_cond.Notify();
            }
        }
        // 消费者获取数据
        void Pop(T *data)
        {
            LockGuard lock(_mutex);
            // 2. 判读缓存是否为空
            while (Isempty())
            {
                _c_count++;
                printf("消费者陷入等待\n");
                // 3. 陷入等待
                _consumer_cond.Wait(_mutex);
                printf("消费者被唤醒\n");
                _c_count--;
            }
            *data = _bq.front(); // 1. 可以直接取走数据吗？？ 不可以!!
            _bq.pop();
            //此时消费者一定知道货架上一定有空位子。
            if (_p_count) //如果有生产者在等待
            {
                printf("唤醒生产者\n");
                _productor_cond.Notify();
            }
        }
        ~Blockqueue()
        {

        }

    private:
        int _cap;
        std::queue<T> _bq;
        Mutex _mutex;
        Cond _productor_cond;
        Cond _consumer_cond;
        int _p_count; // 生产者等待的人数
        int _c_count; // 消费者等待的人数
    };
}